package xaj.weavingtest.ast.istype;

import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

import polyglot.ast.Local;
import polyglot.ast.Node;
import polyglot.ast.Precedence;
import polyglot.ast.TypeNode;
import polyglot.ast.Typed;
import polyglot.types.ReferenceType;
import polyglot.types.SemanticException;
import polyglot.types.TypeSystem;
import polyglot.util.CodeWriter;
import polyglot.util.Position;
import polyglot.visit.NodeVisitor;
import polyglot.visit.PrettyPrinter;
import polyglot.visit.TypeChecker;
import abc.aspectj.ast.ArgPattern;
import abc.aspectj.ast.ArgStar;
import abc.aspectj.ast.PCTarget;
import abc.aspectj.ast.Pointcut_c;
import abc.aspectj.types.AJContext;
import abc.main.Debug;
import abc.weaving.aspectinfo.AbcFactory;

public class PCTarget_c_isType extends Pointcut_c implements PCTarget {
	protected Node pat; // ArgPattern, resolves to Local, TypeNode or ArgStar

    public PCTarget_c_isType(Position pos, ArgPattern pat)  {
	super(pos);
        this.pat = pat;
    }

    public Precedence precedence() {
	return Precedence.LITERAL;
    }
    
    public Set pcRefs() {
    	return new HashSet();
    }
    
    public boolean isDynamic() {
    	return true;
    }
    
	/** Reconstruct the pointcut. */
	protected PCTarget_c_isType reconstruct(Node pat) {
	   if (pat != this.pat) {
		   PCTarget_c_isType n = (PCTarget_c_isType) copy();
		   n.pat = pat;
		   return n;
		}
		return this;
	}

		/** Visit the children of the pointcut. */
	public Node visitChildren(NodeVisitor v) {
		Node pat = (Node) visitChild(this.pat, v);
		return reconstruct(pat);
	}
	
	/** type check the use of  target */
	public Node typeCheck(TypeChecker tc) throws SemanticException {
	   TypeSystem ts = tc.typeSystem();
	   AJContext c = (AJContext) tc.context();

		if (pat instanceof ArgStar)
			return this;
		
		if (! (((Typed)pat).type() instanceof ReferenceType))
		   throw new SemanticException("Argument of \"target\" must be of reference type",pat.position());
		   
		if (c.inDeclare() && !Debug.v().allowDynamicTests)
			throw new SemanticException("target(..) requires a dynamic test and cannot be used inside a \"declare\" statement",position());
		   
		return this;
	}

	public Collection mayBind() throws SemanticException {
			Collection result = new HashSet();
			if (pat instanceof Local) {
				String l = ((Local)pat).name();
	        	if (l == Pointcut_c.initialised)
					throw new SemanticException("cannot explicitly bind local \"" + l + "\"", pat.position());
				result.add(((Local)pat).name());
			}
			 return result;
	}
   
	public Collection mustBind() {
			Collection result = new HashSet();
			if (pat instanceof Local)
						result.add(((Local)pat).name());
			return result;
	}
   
    public void prettyPrint(CodeWriter w, PrettyPrinter tr) {
	w.write("target(");
        print(pat, w, tr);
        w.write(")");
    }
    
	
    public abc.weaving.aspectinfo.Pointcut makeAIPointcut() {
	if (pat instanceof Local) {
		return new TargetVar_isType
		(new abc.weaving.aspectinfo.Var(((Local)pat).name(),((Local)pat).position()),
		 position());
		
	    /*return new abc.weaving.aspectinfo.TargetVar
		(new abc.weaving.aspectinfo.Var(((Local)pat).name(),((Local)pat).position()),
		 position());*/
	} else if (pat instanceof TypeNode) {
		return new TargetType_isType
		 (AbcFactory.AbcType(((TypeNode)pat).type()),
		  position());
		
	    /*return new abc.weaving.aspectinfo.TargetType
		 (AbcFactory.AbcType(((TypeNode)pat).type()),
		  position());*/
	} else if (pat instanceof ArgStar) {
		return new TargetAny_isType(position());
		
	    //return new abc.weaving.aspectinfo.TargetAny(position());
	} else {
	    throw new RuntimeException("Unexpected pattern in target pointcut: "+pat);
	}
    }
}
